/*
 *  Copyright (C) 2004 Cidero, Inc.
 *
 *  Permission is hereby granted to any person obtaining a copy of 
 *  this software to use, copy, modify, merge, publish, and distribute
 *  the software for any non-commercial purpose, subject to the
 *  following conditions:
 *  
 *  The above copyright notice and this permission notice shall be included
 *  in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY IN CONNECTION WITH THE SOFTWARE.
 * 
 *  File: $RCSfile: PrismiqDeviceManager.java,v $
 *
 */

package com.cidero.bridge.prismiq;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;

import org.cybergarage.upnp.device.InvalidDescriptionException;

import com.cidero.bridge.BridgeDeviceManager;
import com.cidero.util.MrUtil;
import com.cidero.util.AppPreferences;

/**
 *
 * This class handles the management of multiple PrismiqMediaRenderer 
 * 'bridge' device instances. The real work with regard to the translation
 * of UPnP commands to their Prismiq 'media agent' equivalents is done in the 
 * PrismiqMediaRenderer class.
 * 
 * 
 * Notes:
 *
 * My Prismiq appears to broadcast UPD packets on port 3650 every
 * 5 seconds that contain the string 'PRISMIQ' in bytes 62-68 of
 * the raw datagram. These packets could perhaps be used for 
 * discovery and timeout detection.  This logic is mostly implemented,
 * but disabled for now for simplicity.
 *
 */
public class PrismiqDeviceManager implements BridgeDeviceManager
//                                             DeviceMonitorListener
{
  private static Logger logger = Logger.getLogger("com.cidero.bridge.prismiq");

  private final static int PRISMIQ_MAX_UNITS = 10;

  //int   heartbeatPort;
  List  activeDeviceList = new ArrayList();

  static AppPreferences pref;


  public PrismiqDeviceManager()
  {
    loadPreferences();

    instantiateDeviceBridges();
  }

  public static void loadPreferences()
  {
    // Load shared & user-specific preferences for this application
    pref = new AppPreferences(".cidero");

    if( ! pref.load( "Bridge", "PrismiqDeviceManager" ) )
    {
      logger.severe("Missing preferences file - exiting");
      System.exit(-1);
    }
  }

  public void savePreferences()
  {
    pref.saveUserPreferences( "Bridge", "PrismiqDeviceManager" );
  }

  public static AppPreferences getPreferences()
  {
    if( pref == null )
      loadPreferences();
    
    return pref;
  }

  /** 
   *  Load device managers specified in property file
   */
  public void instantiateDeviceBridges()
  {
    logger.fine("Entering getProperties " );

    // Default heartbeat port is 3650
    //heartbeatPort = props.getProperty( "heartbeatPort", 3650 );

    for( int n = 1 ; n <= PRISMIQ_MAX_UNITS ; n++ )
    {
      String propPrefix = "prismiq" + n + "_";
      
      String enabled = pref.get( propPrefix + "enabled" );
      if( (enabled == null) || (! enabled.equals("true")) ) 
        continue;
      
      String ipAddr = pref.get( propPrefix + "ipaddr" );
      String name = pref.get( propPrefix + "name" );

      if( ipAddr == null || name == null )
        continue;
      
      logger.info("Creating UPnP bridge for Prismiq Unit '" + name + "'" );
      logger.info("IPAddr = '" + ipAddr + "'" );

      try 
      {
        PrismiqMediaRenderer bridgeDev = 
          new PrismiqMediaRenderer( ipAddr, name );

        activeDeviceList.add( bridgeDev );

        bridgeDev.start();
      }
      catch( InvalidDescriptionException e )
      {
        logger.severe("PrismiqDeviceManager: Invalid UPnP device description" + e );
      }
    }

    logger.fine("Leaving instantiateDeviceBridges " );
  }

  public void start()
  {
    logger.fine("Starting PrismiqDeviceManager " );

    // Start thread that monitors PRISMIQ broadcast port (device discovery
    // & timeout  (Disabled for now)
    //PrismiqDeviceMonitor monitor = 
    //      new PrismiqDeviceMonitor( this, heartbeatPort );
    //    monitor.start();

  }

  public void stop()
  {
    //System.out.println("Stopping PrismiqDeviceManager " );
    logger.info("Stopping PrismiqDeviceManager " );

    for( int n = 0 ; n < activeDeviceList.size(); n++ )
    {
      PrismiqMediaRenderer bridgeDev = 
         (PrismiqMediaRenderer)activeDeviceList.get(n);
      bridgeDev.stop();
    }
  }


  /**
   *  Method invoked by PrismiqDeviceMonitor whenever a UDP packet
   *  arrives on port 3650. If this is a new device, create a 
   *  UPnP <--> Prismiq bridge device instance and add it to the
   *  list of managed devices.
   */

  /*  Disabled for now...
  public void heartbeatPacketReceived( String ipAddr )
  {
    //logger.finest("processing heartbeat packet from " + ipAddr );

    MediaRendererBridge bridgeDev;

    for( int n = 0 ; n < activeDeviceList.size() ; n++ )
    {
      bridgeDev = (MediaRendererBridge)activeDeviceList.get(n);

      if( bridgeDev.getIPAddr().equals( ipAddr ) )
      {
        //logger.finest("Prismiq device at IP " + ipAddr + " updated" );

        return;
      }

    }
    
    //
    // No existing device for this IP - add one and start it running
    //

    logger.info("Found new Prismiq device at IP: " + ipAddr +
                " - creating UPnP bridge" );

    try 
    {
      bridgeDev = 
        new MediaRendererBridge( new PrismiqMediaRenderer( ipAddr ) );

      activeDeviceList.add( bridgeDev );

      bridgeDev.start();
    }
    catch( InvalidDescriptionException e )
    {
      logger.severe("PrismiqDeviceManager: Invalid UPnP device description" );
    }
    
  }
  */


  public static void main(String args[])
  {
    PrismiqDeviceManager devManager = new PrismiqDeviceManager();

    devManager.start();
  }
  

}

